module arm.bus;

/**
* MMIO总线抽象类
*/

import arm.misc:combineStr;
//import chip:Peripherals;
//import std.traits:getUDAs;
import core.volatile;
import core.bitop:bsf,bsr;
import core.atomic;
///import arm:BitBand;

import std.traits :isSomeString,isPointer;
import std.meta : allSatisfy;

package{
    /// 回调函数定义
    alias IRQHandler = void function();


    /**
    * 枚举,构建初始化顺序 SYSCFG -> PWR -> Flash -> NVIC -> SCB -> RCC -> STK -> Other
    */
    enum FlagCrt
    {
        ROOT = 0,
        /// SYSCFG 优先级
        SYSCFG =10,
        /// PWR 优先级
        PWR = 20,
        /// Flash
        FLASH = 40,
        /// NVIC
        NVIC = 60,
        /// SCB
        SCB = 80,
        /// RCC
        RCC = 100,
        /// STK
        STK = 120,
        /// Other
        Other = 200,
    }
    /// 优先级模板
    template CrtPriority(FlagCrt f,ubyte n)
    {
        enum CrtPriority = ( f << 8 | n);
    }
}

public
{
    /**
    * 外设流接口
    */
    interface PeriStream : MemoryStream
    {

    }
    interface MemoryStream
    {
        /**
        * 读取数据
        * Params:
        *  dst = 目标地址
        *  n = 读取的字节数
        * Returns:
        * 返回读取的字节数
        */
        size_t reads(void* dst,size_t n);
        /**
        * 写入数据
        * Params:
        *  src = 源地址
        *  n = 写入的字节数
        */
        void writes(immutable(char)* src, size_t n);
        
        //interface write(immutable(char)*, int);
    }

}

auto abs(T)(T v)
if (imported!"std.traits".isSigned!T)
{
    return cast(Unsigned!T) (v < 0 ? -v : v);
}


/**
* 抽象基类
* Params:
*   mPeri = MMIO总线的外设
* todo: 考虑使用 offsetof 检查 UDA 中的 oset
*/
deprecated
abstract class MMIOBus(alias mPeri)
{
    private {
        /// 检查是否是有效的寄存器
        template CheckReg(string rn)
        {
            enum CheckReg = __traits(hasMember,mPeri,rn);
        }
        /// 检查是否是有效的位域标记
        template CheckBitfield(string rn,string fn) if(CheckReg!(rn))
        {
            enum CheckBitfield = __traits(hasMember,__traits(getMember,mPeri,combineStr!("mask_",rn)),fn);
        }

        template getRegister(string rn)
        {
            enum uda = __traits(getAttributes, __traits(getMember,mPeri,rn));
            static if(uda.length == 1)
                enum getRegister = uda[0];
            else
                static assert(0,"Register uda error");
        }
        /// 位域宽度
        template FieldWidth(size_t mask)
        {
            enum FieldWidth = bsr(mask) - bsf(mask) + 1;
        }

        /// 
        template getAddress(string rn)
        {
            enum getAddress = cast(size_t)&(__traits(getMember,mPeri,rn));
        }
        /// 寄存器有效掩码
        template RegMaskA(string rn,T...) //if (T.length > 0)
        {
            static if(T.length > 0){
                enum RegMaskA = FieldMask!(rn,T[0]) | RegMaskA!(rn,T[1..$]);
            }else{
                enum RegMaskA = 0;
            }

        }

    }

    package{
        /**
        * 获取寄存器所有有效掩码
        * Params:
        *   mn = 寄存器名
        */
        template RegMask(string rn) //if(__traits(hasMember,mPeri,rn) == true)
        {
            enum RegMask = RegMaskA!(rn,__traits(allMembers, __traits(getMember,mPeri,combineStr!("mask_",rn))));
        }
        /// 换算地址
        template GetBitBand(string rn,string fn)
        {            
            enum GetBitBand = BitBand!(&(__traits(getMember,mPeri,rn)),FieldPos!(FieldMask!(rn,fn)));
            static assert(GetBitBand,"Bitband address error: "~fn~" for "~rn);
        }
        /// 掩码右侧起始位
        template FieldPos(size_t mask)
        {
            enum FieldPos = bsf(mask);
        }
        /// 返回掩码名对应的值
        template FieldMask(string rn,string fn)
        {
            enum FieldMask = __traits(getMember,__traits(getMember,mPeri,combineStr!("mask_",rn)),fn);
        }
       
    }
    public
    {
        /// 设定回调函数
        static void MMIO_SetHandler()
        {
            //Peripherals.setHandler!(mPeri);
        }
        /// 读取回调函数
        static void MMIO_GetHandler()
        {
            //Peripherals.getHandler!(mPeri);
        }
        static interface Monitor
        {
            static void lock(){

            };
            static void unlock(){};
            static bool tryLock(){
                return true;
            };
        }
        
    }
}

/// 作废
deprecated("已经由新的 volatile!(T) 替代相关功能")
package{
    //import core.volatile;
    import arm.utils;
    import arm.misc;
    import core.atomic;
    import arm.bitband;
    
    /**
            enum BitBandAddr = BitBand!(addr,pos);
        volatile2 a;
    */
    /// bitBand 方式操作寄存器位 if(HasBitBand)
    static void BitBand_Set(size_t addr,size_t pos,bool _volatile = false )(uint val)
    if(CheckBitBandable(addr))
    {
        enum pDst = BitBand!(addr,pos);
        enum check = CheckBitBandable(addr);
        enum paddr = RegMap!(pDst,shared(uint));
        //enum RegMap = RegMap!(0x4002_1000,ushort);
        //static assert(bitband != 0,"Bitband address error");
        static if(_volatile){
            //volatileStore((RegMap!(pDst,uint)),val);
            atomicStore(*paddr,val);
        }else{
            *(RegMap!(pDst,uint)) = val;
        }
    }
    /// 切换电平
    static void BitBand_Toggle(size_t addr,size_t pos,bool _volatile = false )()
    if(CheckBitBandable(addr))
    {
        enum pDst = BitBand!(addr,pos);
        enum check = CheckBitBandable(addr);
        enum paddr = RegMap!(pDst,shared(uint));

        static if(_volatile){
            //volatileStore((RegMap!(pDst,uint)),val);
            atomicOp!("^=")(*paddr,1);
        }else{
            *(RegMap!(pDst,uint)) ^= val;
        }
    }
    static bool BitBand_Get(size_t addr,size_t pos,bool _volatile = false )()
    if(CheckBitBandable(addr))
    {
        enum pDst = BitBand!(addr,pos);
        enum check = CheckBitBandable(addr);
        enum paddr = RegMap!(pDst,shared(uint));
        static if(_volatile){
            //volatileStore((RegMap!(pDst,uint)),val);
            //atomicOp!("^=")(*paddr,1);
            return cast(bool)atomicLoad(*paddr);
        }else{
            return cast(bool)*(RegMap!(pDst,uint)) ;
        }
    }
    //static void BitBand_Clr
}
